package com.yn.xgame;

import com.google.protobuf.ByteString;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.slf4j.Logger;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

abstract public class DBHandler {

    public QueryRunner m_runner;
    public Connection m_conn;
    public MapListHandler handler = new MapListHandler();
    public MapHandler mapHandler = new MapHandler();

    public DBHandler(){}
    public DBHandler(QueryRunner runner, Connection conn) {
        m_runner = runner;
        m_conn = conn;
    }

    public abstract Logger logger();

    public void sqlRollBack(Object msg) {
        try {
            m_conn.rollback();
        } catch (SQLException e) {
            logger().error("roll back failed", msg);
        }
    }

    public long getLong(Map<String, Object> map, String key) {
        return (long) map.get(key);
    }

    public long getTimeLong(Map<String, Object> map, String key)
    {
        return ((Timestamp)(map.get(key))).getTime();
    }

    public int getInt(Map<String, Object> map, String key) {
        return (int) map.get(key);
    }

    public String getString(Map<String, Object> map, String key) {
        return (String) map.get(key);
    }

    public ByteString getBlobByte(Map<String, Object> one, String key) throws SQLException {
        byte[] data = (byte[]) one.get(key);
        return ByteString.copyFrom(data);
    }

    public int getBigDecimalToInt(Map<String, Object> one, String key) {
        BigDecimal d = (BigDecimal) one.get(key);
        return d.intValue();
    }

    // 转换器，sql, args 输出查询结果，map -> R 转换，R 结果消费
    public <R> void listFactor(String sql, Function<Map<String, Object>, R> mapFunc, Consumer<R> resultConsumer) {
        listFactor(sql, null, mapFunc, resultConsumer);
    }

    // 查询list结果集
    public <R> List<R> queryList(String sql, Class<R> clazz) throws SQLException {
        BeanListHandler<R> handler = new BeanListHandler<>(clazz);
        return m_runner.query(m_conn, sql, handler);
    }

    // 查询list结果集
    public <R> List<R> queryList(String sql, Class<R> clazz, Object[] args) throws SQLException {
        BeanListHandler<R> handler = new BeanListHandler<>(clazz);
        return m_runner.query(m_conn, sql, handler, args);
    }

    // 查询单条对象
    public <R> R queryOne(String sql, Class<R> clazz) throws SQLException {
        BeanHandler<R> handler = new BeanHandler<>(clazz);
        return m_runner.query(m_conn, sql, handler);
    }

    // 查询单条对象
    public <R> R queryOne(String sql, Class<R> clazz, Object[] args) throws SQLException {
        BeanHandler<R> handler = new BeanHandler<>(clazz);
        return m_runner.query(m_conn, sql, handler, args);
    }

    // 查询单条对象
    public Map<String, Object> queryOne(String sql) throws SQLException {
        return m_runner.query(m_conn, sql, mapHandler);
    }

    // 查询单条对象
    public Map<String, Object> queryOne(String sql, Object[] args) throws SQLException {
        return m_runner.query(m_conn, sql, mapHandler, args);
    }
    
    public int saveUpdate(String sql, Object[] args) throws SQLException {
    	return m_runner.update(m_conn, sql, args);
    }
    
    public int saveUpdate(String sql) throws SQLException {
    	return m_runner.update(m_conn, sql);
    }

    public <R> int listFactor(String sql, Object[] args, Function<Map<String, Object>, R> mapFunc, Consumer<R> resultConsumer) {
        try {
            List<Map<String, Object>> list;
            if (args == null) {
                list = m_runner.query(m_conn, sql, handler);
            } else {
                list = m_runner.query(m_conn, sql, handler, args);
            }
            list.stream().map(mapFunc).forEach(resultConsumer);
            return list.size();
        } catch (Exception e) {
            logger().error("factor sql error: {}, args: ", sql, args);
            logger().error("", e);
            return 0;
        }
    }

    public <R> boolean oneFactor(String sql, Function<Map<String, Object>, R> mapFunc, Supplier<R> ifNull, Consumer<R> resultConsumer) {
        return oneFactor(sql, null, mapFunc, ifNull, resultConsumer);
    }
    public <R> boolean oneFactor(String sql, Object[] args, Function<Map<String, Object>, R> mapFunc, Supplier<R> ifNull, Consumer<R> resultConsumer) {
        try {
            Map<String, Object> map;
            if (args == null) {
                map = m_runner.query(m_conn, sql, mapHandler);
            } else {
                map = m_runner.query(m_conn, sql, mapHandler, args);
            }
            R r;
            if (map == null || map.isEmpty()) {
                r = ifNull.get();
            } else {
                r = mapFunc.apply(map);
            }
            resultConsumer.accept(r);
            return true;
        } catch (Exception e) {
            logger().error("factor sql error: {}, args: ", sql, args);
            logger().error("", e);
            return false;
        }
    }

}
